/**
 * 开源版本请务必保留此注释头信息，若删除捷码开源〔GEMOS〕官方保留所有法律责任追究！
 * 本软件受国家版权局知识产权以及国家计算机软件著作权保护（登记号：2018SR503328）
 * 不得恶意分享产品源代码、二次转售等，违者必究。
 * Copyright (c) 2020 gemframework all rights reserved.
 * http://www.gemframework.com
 * 版权所有，侵权必究！
 */
package com.gemframework.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gemframework.common.config.GemSystemProperties;
import com.gemframework.common.exception.GemException;
import com.gemframework.common.utils.GemBeanUtils;
import com.gemframework.common.utils.GemRedisUtils;
import com.gemframework.common.utils.GemStringUtils;
import com.gemframework.model.common.BaseEntityVo;
import com.gemframework.model.common.BaseResultData;
import com.gemframework.model.common.PageInfo;
import com.gemframework.model.common.ZtreeEntity;
import com.gemframework.model.entity.po.User;
import com.gemframework.model.enums.ExceptionCode;
import com.gemframework.model.enums.StatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.*;

import static com.gemframework.common.constant.GemRedisKeys.Auth.USER_ROLES;
import static com.gemframework.common.constant.GemSessionKeys.CURRENT_USER_KEY;

@Slf4j
public class BaseController {

    @Autowired
    GemRedisUtils gemRedisUtils;

    @Autowired
    GemSystemProperties gemSystemProperties;

    public static Page setOrderPage(PageInfo pageInfo) {
        if(pageInfo.getPage() == null){
            pageInfo.setPage(1L);
        }
        if(pageInfo.getLimit() == null){
            pageInfo.setLimit(10L);
        }
        OrderItem orderItem = new OrderItem();
        //默认排序
        orderItem.setColumn("sort_number").setAsc(true);
        orderItem.setColumn("create_time").setAsc(false);

        if(pageInfo.getSort_order()!=null && pageInfo.getSort_order().size()>0){
            for(String orderStr:pageInfo.getSort_order()){
                String[] orders = orderStr.split(",");
                if(orders.length==2){
                    if(orders[1].equalsIgnoreCase("asc")){
                        orderItem.setColumn(orders[0]).setAsc(false);
                    }else{
                        orderItem.setColumn(orders[0]).setAsc(false);
                    }
                }
            }
        }

        List orders = new ArrayList();
        orders.add(orderItem);
        Page page = new Page();
        page.setOrders(orders);
        page.setSize(pageInfo.getLimit());
        page.setCurrent(pageInfo.getPage());
        return page;
    }

    public static QueryWrapper setSort(PageInfo pi) {
        QueryWrapper queryWrapper = setSort();
        if(pi.getSort_order()!=null && pi.getSort_order().size()>0){
            for(String orderStr:pi.getSort_order()){
                String[] orders = orderStr.split("|");
                if(orders.length==2){
                    if(orders[1].equalsIgnoreCase("asc")){
                        queryWrapper.orderByAsc(orders[0]);
                    }else{
                        queryWrapper.orderByDesc(orders[0]);
                    }
                }
            }
        }
        return queryWrapper;
    }

    public static QueryWrapper setSort() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.orderByAsc("sort_number");
        return queryWrapper;
    }

    public static QueryWrapper makeQueryMaps(BaseEntityVo vo) {
        QueryWrapper queryWrapper = setSort();
        queryWrapper.eq("deleted", StatusEnum.NORMAL.getCode());
        Map<String,Object> map = GemBeanUtils.objectToMap(vo);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String fieldName = GemStringUtils.humpToLine(entry.getKey());
            Object paramVal = entry.getValue();
            log.debug("key= " + fieldName + " and value= "+paramVal);
            if(entry.getKey().equalsIgnoreCase("updateStartDate") || entry.getKey().equalsIgnoreCase("updateStartTime")){
                queryWrapper.ge(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"update_time",paramVal);
            }else if(entry.getKey().equalsIgnoreCase("updateEndDate") || entry.getKey().equalsIgnoreCase("updateEndTime")){
                queryWrapper.le(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"update_time",paramVal);
            }else if(entry.getKey().equalsIgnoreCase("createStartDate") || entry.getKey().equalsIgnoreCase("createStartTime")){
                queryWrapper.ge(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"create_time",paramVal);
            }else if(entry.getKey().equalsIgnoreCase("createEndDate") || entry.getKey().equalsIgnoreCase("createEndTime")){
                queryWrapper.le(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"create_time",paramVal);
            }else{
                 //如果是数字
                if(paramVal instanceof Integer || paramVal instanceof Long){
                    queryWrapper.eq(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),fieldName,paramVal);
                }else{
                    queryWrapper.like(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),fieldName,paramVal);
                }
            }
        }
        return queryWrapper;
    }

    public static QueryWrapper makeQueryMaps(BaseEntityVo vo,PageInfo pi) {
        QueryWrapper queryWrapper = setSort(pi);
        queryWrapper.eq("deleted",StatusEnum.NORMAL.getCode());
        Map<String,Object> map = GemBeanUtils.objectToMap(vo);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String fieldName = GemStringUtils.humpToLine(entry.getKey());
            Object paramVal = entry.getValue();
            log.debug("key= " + fieldName + " and value= "+paramVal);
            if(entry.getKey().equalsIgnoreCase("startDate")){
                queryWrapper.ge(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"update_time",paramVal);
            }else if(entry.getKey().equalsIgnoreCase("endDate")){
                queryWrapper.le(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),"update_time",paramVal);
            }else{
                 //如果是数字
                if(paramVal instanceof Integer || paramVal instanceof Long){
                    queryWrapper.eq(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),fieldName,paramVal);
                }else{
                    queryWrapper.like(paramVal != null && StringUtils.isNotBlank(String.valueOf(paramVal)),fieldName,paramVal);
                }
            }
        }
        return queryWrapper;
    }


    /**
     * 将list格式是权限数据，转化成tree格式的权限数据。
     * @param treeNodes 传入的树节点列表
     * @return
     */
    public static List<ZtreeEntity> toTree(List<ZtreeEntity> treeNodes) {
        List<ZtreeEntity> trees = new ArrayList<ZtreeEntity>();
        for (ZtreeEntity treeNode : treeNodes) {
            if (-1 == (treeNode.getPid())) {
                trees.add(treeNode);
            }
            for (ZtreeEntity it : treeNodes) {
                if (it.getPid().longValue() == treeNode.getId().longValue()) {
                    if (treeNode.getChildren() == null) {
                        treeNode.setChildren(new ArrayList<ZtreeEntity>());
                    }
                    treeNode.getChildren().add(it);
                }
            }
        }
        return trees;
    }


    public static List<ZtreeEntity> initRootTree() {
        List<ZtreeEntity> ztreeEntities = new ArrayList<>();
        ZtreeEntity ztreeEntity = ZtreeEntity.builder()
                .id(0L)
                .pid(-1L)
                .name("顶层目录|全选/全消")
                .title("顶层目录|全选/全消")
                .level(0)
                .open(true)
                .nocheck(true)
                .build();
        ztreeEntities.add(ztreeEntity);

        return ztreeEntities;
    }

    public static void GemValidate(Object object, Class<?>... groups){
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next();
            throw new GemException(ExceptionCode.PARAM_EXCEPTION.getCode(),constraint.getMessage());
        }
    }

    protected User getUser() {
        return (User) SecurityUtils.getSubject().getSession().getAttribute(CURRENT_USER_KEY);
    }

    protected String getUsername() {
        return (String)SecurityUtils.getSubject().getPrincipal();
    }

    protected Set<String> getRolesFlag() {
        String userName = (String)SecurityUtils.getSubject().getPrincipal();
        //如果Redis集群开启则从redis中取
        if(gemSystemProperties.isCluster()){
            return (Set<String>) gemRedisUtils.get(userName + "_" + USER_ROLES);
        }else{
            return (Set<String>) SecurityUtils.getSubject().getSession().getAttribute(userName + "_" + USER_ROLES);
        }
    }


    @ExceptionHandler(Exception.class)
    @ResponseBody
    public BaseResultData handleExp(HttpServletRequest request, Exception ex) {
        //ex.printStackTrace();
        ExceptionCode exceptionCode = null;
        if (ex instanceof GemException) {
            log.error("GemException: code:{},msg:{}" ,((GemException) ex).getCode(), ex.getMessage());
            GemException gemException = (GemException) ex;
            return BaseResultData.ERROR(gemException.getCode(), gemException.getMessage());
        }else if (ex instanceof UnauthorizedException){
            exceptionCode = ExceptionCode.PERMISSION_DENIED;
        }else{
            exceptionCode = ExceptionCode.SYSTEM_EXCEPTION;
        }
        log.error("System Exception: code:{},msg:{}" , exceptionCode.getCode(),exceptionCode.getMsg());
        ex.printStackTrace();
        return BaseResultData.ERROR(exceptionCode);
    }

}